package com.xixi.core.rpc.proxy;

import cn.hutool.core.collection.CollUtil;
import com.xixi.core.rpc.RpcApplication;
import com.xixi.core.rpc.config.RpcConfig;
import com.xixi.core.rpc.constant.RpcConstant;
import com.xixi.core.rpc.fault.retry.RetryStrategy;
import com.xixi.core.rpc.fault.retry.RetryStrategyFactory;
import com.xixi.core.rpc.fault.tolerant.TolerantStrategy;
import com.xixi.core.rpc.fault.tolerant.TolerantStrategyFactory;
import com.xixi.core.rpc.loadbalancer.LoadBalancer;
import com.xixi.core.rpc.loadbalancer.LoadBalancerFactory;
import com.xixi.core.rpc.model.RpcRequest;
import com.xixi.core.rpc.model.RpcResponse;
import com.xixi.core.rpc.model.ServiceMetaInfo;
import com.xixi.core.rpc.registry.Registry;
import com.xixi.core.rpc.registry.RegistryFactory;
import com.xixi.core.rpc.serializer.CustomSerializer;
import com.xixi.core.rpc.serializer.CustomSerializerFactory;
import com.xixi.core.rpc.server.tcp.VertxTcpClient;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;

/**
 * @author: zxh
 * @date: 2024/8/21 14:06
 * @description: 动态代理
 */
public class ServiceProxy implements InvocationHandler {

	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		// 指定序列化器
		// CustomSerializer serializer = new CustomJdkSerializer();
		// 动态序列化器
		final CustomSerializer serializer = CustomSerializerFactory.getInstance(RpcApplication.getRpcConfig().getSerializer());

		System.out.println("代理方法：" + method.getName());

		String serviceName = method.getDeclaringClass().getName();
		// 构造请求
		RpcRequest rpcRequest = RpcRequest.builder()
				.serviceName(serviceName)
				.methodName(method.getName())
				.parameterTypes(method.getParameterTypes())
				.args(args)
				.build();
		// 序列化
		// byte[] bodyBytes = serializer.serialize(rpcRequest);

		// 从注册中心获取服务提供者请求地址
		RpcConfig rpcConfig = RpcApplication.getRpcConfig();
		System.out.println(rpcConfig.getRegistryConfig().getRegistry());
		Registry registry = RegistryFactory.getInstance(rpcConfig.getRegistryConfig().getRegistry());
		ServiceMetaInfo serviceMetaInfo = new ServiceMetaInfo();
		serviceMetaInfo.setServiceName(serviceName);
		serviceMetaInfo.setServiceVersion(RpcConstant.DEFAULT_SERVICE_VERSION);
		List<ServiceMetaInfo> serviceMetaInfoList = registry.serviceDiscovery(serviceMetaInfo.getServiceKey());
		if (CollUtil.isEmpty(serviceMetaInfoList)) {
			throw new RuntimeException("暂无服务地址");
		}
		// 暂时先取第一个
		// ServiceMetaInfo selectedServiceMetaInfo = serviceMetaInfoList.get(0);

		// 负载均衡
		LoadBalancer loadBalancer = LoadBalancerFactory.getInstance(rpcConfig.getLoadBalancer());
		// 将调用方法（请求路径）作为负载均衡参数
		Map<String, Object> requestParams = new HashMap<>();
		requestParams.put("methodName", rpcRequest.getMethodName());
		ServiceMetaInfo selectedServiceMetaInfo = loadBalancer.select(requestParams, serviceMetaInfoList);

		// 发送请求（HTTP）
		/*try (HttpResponse httpResponse = HttpRequest.post(selectedServiceMetaInfo.getServiceAddress())
				.body(bodyBytes)
				.execute()) {
			byte[] result = httpResponse.bodyBytes();
			// 反序列化
			RpcResponse rpcResponse = serializer.deserialize(result, RpcResponse.class);
			return rpcResponse.getData();
		}*/
		// 发送TCP请求
		/*Vertx vertx = Vertx.vertx();
		NetClient netClient = vertx.createNetClient();
		CompletableFuture<RpcResponse> responseFuture = new CompletableFuture<>();
		netClient.connect(selectedServiceMetaInfo.getServicePort(), selectedServiceMetaInfo.getServiceHost(),
				result -> {
					if (result.succeeded()) {
						System.out.println("Connected to TCP server");
						NetSocket socket = result.result();
						// 发送数据
						// 构造消息
						ProtocolMessage<RpcRequest> protocolMessage = new ProtocolMessage<>();
						ProtocolMessage.Header header = new ProtocolMessage.Header();
						header.setMagic(ProtocolConstant.PROTOCOL_MAGIC);
						header.setVersion(ProtocolConstant.PROTOCOL_VERSION);
						header.setSerializer((byte) Objects.requireNonNull(ProtocolMessageSerializerEnum.getEnumByValue(RpcApplication.getRpcConfig().getSerializer())).getKey());
						header.setType((byte) ProtocolMessageTypeEnum.REQUEST.getKey());
						header.setRequestId(IdUtil.getSnowflakeNextId());
						protocolMessage.setHeader(header);
						protocolMessage.setBody(rpcRequest);
						// 编码请求
						try {
							System.out.println("开始代理请求数据编码");
							Buffer encode = ProtocolMessageEncoder.encode(protocolMessage);
							System.out.println("代理请求数据编码完成： " + encode.length());
							socket.write(encode);
						} catch (IOException e) {
							throw new RuntimeException("协议消息编码错误");
						}

						// 接收响应
						socket.handler(buffer -> {
							try {
								System.out.println("开始代理请求响应解码：" + buffer.length());
								ProtocolMessage<RpcResponse> decode = (ProtocolMessage<RpcResponse>) ProtocolMessageDecoder.decode(buffer);
								System.out.println("代理请求响应解码完成");
								responseFuture.complete(decode.getBody());
							} catch (IOException e) {
								throw new RuntimeException("协议消息解码错误");
							}
						});
					} else {
						System.err.println("Failed to connect to TCP server");
					}
				});
		RpcResponse rpcResponse = responseFuture.get();
		netClient.close();
		return rpcResponse.getData();*/
		RpcResponse rpcResponse = new RpcResponse();
		// 使用重试机制
		try {
			RetryStrategy retryStrategy = RetryStrategyFactory.getInstance(rpcConfig.getRetryStrategy());
			// RpcResponse rpcResponse = VertxTcpClient.doRequest(rpcRequest, selectedServiceMetaInfo);
			rpcResponse = retryStrategy.doRetry(() -> VertxTcpClient.doRequest(rpcRequest, selectedServiceMetaInfo));
		} catch (Exception e) {
			// 容错机制
			TolerantStrategy tolerantStrategy = TolerantStrategyFactory.getInstance(rpcConfig.getTolerantStrategy());
			rpcResponse = tolerantStrategy.doTolerant(null, e);
		}
		return rpcResponse.getData();
	}
}
